﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Microsoft.Samples.ServiceHosting.StorageClient;

namespace Astoman.Common
{
    /// <summary>
    /// This class is a wrapper around an Azure Storage Account (StorageAccountInfo class) so it can serialize itself to XML.
    /// It also has methods to load these settings again and return StorageAccountInfo for Table, Blob and Queue
    /// </summary>
    [XmlRoot]
    public class AzureStorageAccount
    {
        //TODO Add hardcoded Getter for development settings (devstoreaccount1)
        [XmlIgnore]
        public static String SavePath { get; set; }

        [XmlIgnore]
        public const String BaseUriTable = "http://table.core.windows.net";
        [XmlIgnore]
        public const String BaseUriBlob = "http://blob.core.windows.net";
        [XmlIgnore]
        public const String BaseUriQueue = "http://queue.core.windows.net";

        private const String FilePrefix = "[AccountSetting]";
        private const String FileEnding = ".xml";

        public String AccountName { get; set; }
        public String SharedKey { get; set; }

        private String _settingName = null;
        /// <summary>
        /// Get the name of this setting
        /// </summary>
        public String SettingName
        {
            get
            {
                if (String.IsNullOrEmpty(_settingName))
                {
                    _settingName = AccountName;
                }
                return _settingName;
            }
            set { _settingName = value; }
        }

        /// <summary>
        /// Get the filename of this setting
        /// </summary>
        [XmlIgnore]
        public String FileName
        {
            get
            {
                return GetFileName(SettingName);
            }
        }

        private static String GetFileName(String settingName)
        {
            String ending = FileEnding;
            if (settingName.Contains(ending)) ending = "";
            return String.Format("{0}{1}{2}", FilePrefix, settingName.ToUpper(), ending);
        }

        /// <summary>
        /// Create a new Account by specifying account name and shared key.
        /// </summary>
        /// <param name="accountName">Account name for a storage account from Azure portal</param>
        /// <param name="sharedKey">Shared key for a storage account from Azure portal</param>
        /// <returns></returns>
        public static AzureStorageAccount Create(String accountName, String sharedKey)
        {
            
            AzureStorageAccount setting = new AzureStorageAccount();
            setting.AccountName = accountName;
            setting.SharedKey = sharedKey;
            
            return setting;
        }

        /// <summary>
        /// Save to disk using the SavePath
        /// </summary>
        /// <param name="setting">The settings object to be serialized</param>
        public static void Save(AzureStorageAccount setting)
        {
            using (var stream = File.OpenWrite(Path.Combine(SavePath, setting.FileName)))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(AzureStorageAccount));
                serializer.Serialize(stream, setting);
            }
        }

        public static String ValidateSetting(String accountName, String sharedKey)
        {
            StringBuilder errorString = new StringBuilder();
            if (String.IsNullOrEmpty(accountName) || String.IsNullOrEmpty(sharedKey))
            {
                errorString.Append("Enter values for account name and shared key before trying to save.");
            }
            else
            {
                //Validate shared key format
                try
                {
                    Convert.FromBase64String(sharedKey);
                }
                catch (Exception)
                {
                    errorString.Append("Shared key is not in Base64 format. ");
                }

                //Validate account name
                if (String.Compare(accountName.ToLowerInvariant(), accountName, false) != 0)
                {
                    errorString.Append("Account name must be lowercase. ");
                }
            }

            String errorMessage = errorString.ToString();
            return String.IsNullOrEmpty(errorMessage) ? null : errorMessage;
        }


        /// <summary>
        /// Loads the names of all AzureStorageAccounts from the SavePath
        /// </summary>
        /// <returns></returns>
        public static List<String> GetAllSettingNames(String appStartupPath)
        {
            DirectoryInfo dirInfo;
            if(String.IsNullOrEmpty(SavePath)){
                dirInfo = new DirectoryInfo(appStartupPath);
            }else{
                dirInfo = new DirectoryInfo(SavePath);
            }
            var filenames = (from file in dirInfo.GetFiles()
                            where file.Name.StartsWith(FilePrefix)
                            select file.Name).ToList();
            
            var settingNames = new List<String>();
            filenames.ForEach(x => settingNames.Add(LoadSetting(x).SettingName));
            return settingNames;
        }

        /// <summary>
        /// Loads a setting from the SavePath
        /// </summary>
        /// <param name="settingName">The name of the setting to look for</param>
        /// <returns></returns>
        public static AzureStorageAccount LoadSetting(String settingName)
        {
            String filename;
            if (settingName.Contains(FileEnding))
            {
                filename = settingName;
            }
            else
            {
                filename = GetFileName(settingName);
            }

            try
            {
                using (var stream = File.OpenRead(Path.Combine(SavePath, filename)))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(AzureStorageAccount));
                    return (AzureStorageAccount)serializer.Deserialize(stream);
                }
            }
            catch (Exception ex)
            {

            }
            return null;
        }

        /// <summary>
        /// Gets the StorageAccountInfo that can be used for operations against TableStorage
        /// </summary>
        [XmlIgnore]
        public StorageAccountInfo TableStorageAccountInfo
        {
            get { return new StorageAccountInfo(new Uri(BaseUriTable), null, AccountName, SharedKey); }
        }

        /// <summary>
        /// Gets the StorageAccountInfo that can be used for operations against BlobStorage
        /// </summary>
        [XmlIgnore]
        public StorageAccountInfo BlobStorageAccountInfo
        {
            get { return new StorageAccountInfo(new Uri(BaseUriBlob), null, AccountName, SharedKey); }
        }

        /// <summary>
        /// Gets the StorageAccountInfo that can be used for operations against QueueStorage
        /// </summary>
        [XmlIgnore]
        public StorageAccountInfo QueueStorageAccountInfo
        {
            get { return new StorageAccountInfo(new Uri(BaseUriQueue), null, AccountName, SharedKey); }
        }
    }
}
